/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package assignment2;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;

/**
 * ProductEditor Class:
 * This class is used to edit the currently selected product from the ProductViewer menu
 * @author Vale
 *
 */
public class ProductEditor implements ActionListener, WindowListener {
    private JFrame editProdFrame;
    private JScrollPane currInvSP;
    private JScrollPane prodInvSP;
    private JPanel headingPanel;
    private JPanel buttonPanel;
    private JPanel centralPanel;
    private JButton doneButton;
    private JButton cancelButton;
    private JButton addButton;
    private JButton remButton;
    private Product currentProduct;
    private Product prodRestore;
    private InventoryList inventory;
    private JTextField prodName;
    private JTextField prodCost;
    private JTextField prodSched;
    private DefaultListModel currInvLM = new DefaultListModel();
    private DefaultListModel prodInvLM = new DefaultListModel();
    private JList currInvList;
    private JList prodInvList;
    private JFrame currViewer;
    private ProductList products;
    private int currProdInd;
    private static final String HEADING_FONT = "Heading";
    private static final int HEADING_FONT_SIZE = 20;
    private static final String FRAME_HEADING = "Edit Product";
    private static final String GUI_TITLE = "Edit Product";
    private static final String DONE_BUTTON = "Done";
    private static final String ADD_BUTTON = "Add";
    private static final String CANCEL_BUTTON = "Cancel";
    private static final String REM_BUTTON = "Remove";
    private static final int BPANEL_ROWS = 1;
    private static final int BPANEL_COLS = 2;
    private static final int BUTTON_SPACING = 5;
    private static final int CPANEL_ROWS = 4;
    private static final int CPANEL_COLS = 2;
    private static final String INVLIST_HEAD = "Current Inventory";
    private static final String PRODINV_HEAD = "Product Inventory";
    private static final String PROD_NAME = "Product Name";
    private static final String PROD_COST = "Product Cost";
    private static final String PROD_SCHED = "Products Scheduled";
    private static final int ZERO = 0;
    private final String ERR = "Error";
    private final String INCORRECT_INPUT = "Incorrect Input";
    private static final String EMPTY_STRING = "";
    private final String NO_INV = "No Inventory Specified";
    private final String NO_INV_ITEM = "No Inventory Item Selected";

    /**
     * ProductEditor Constructor:
     * This is the constructor for the ProductEditor class. It takes a number of inputs, which are used to modify the current product and then place it back in the product list.
     *
     */
    public ProductEditor(Product currProd, ProductList prodList, InventoryList currInv, JFrame prodViewer) {
        //Create new Objects
        currViewer = prodViewer;
        products = prodList;
        currentProduct = currProd;
        prodRestore = currProd;
        inventory = currInv;
        currProdInd = products.getIndex(currentProduct);
        prodList.remove(currProdInd);
        prodName = new JTextField();
        prodCost = new JTextField();
        prodSched = new JTextField();
        editProdFrame = new JFrame(FRAME_HEADING);
        headingPanel = new JPanel();
        buttonPanel = new JPanel();
        addButton = new JButton(ADD_BUTTON);
        remButton = new JButton(REM_BUTTON);
        doneButton = new JButton(DONE_BUTTON);
        cancelButton = new JButton(CANCEL_BUTTON);
        centralPanel = new JPanel();

        //Edit Frames properties
        editProdFrame.addWindowListener(this);
        editProdFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        editProdFrame.setLayout(new BorderLayout());

        //Format Heading
        JTextArea heading = new JTextArea(GUI_TITLE);
        Color bgColour = editProdFrame.getBackground();
        heading.setBackground(bgColour);
        Font headerFont = new Font(HEADING_FONT, Font.BOLD, HEADING_FONT_SIZE);
        heading.setFont(headerFont);
        headingPanel.add(heading);

        //Add Buttons
        buttonPanel.setLayout(new GridLayout(BPANEL_ROWS,BPANEL_COLS,BUTTON_SPACING,BUTTON_SPACING));
        buttonPanel.add(doneButton);
        doneButton.addActionListener(new DoneButton());
        buttonPanel.add(cancelButton);
        cancelButton.addActionListener(this);

        //Set up central Pane
        centralPanel.setLayout(new BorderLayout());

        JPanel centralNPanel = new JPanel();
        centralNPanel.setLayout(new GridLayout(CPANEL_ROWS,CPANEL_COLS,BUTTON_SPACING,BUTTON_SPACING));
        centralNPanel.add(new JLabel(PROD_NAME));
        prodName.setText(currProd.getProdName());
        centralNPanel.add(prodName);
        centralNPanel.add(new JLabel(PROD_COST));
        prodCost.setText(String.valueOf(currProd.getProdCost()));
        centralNPanel.add(prodCost);
        centralNPanel.add(new JLabel(PROD_SCHED));
        prodSched.setText(String.valueOf(currProd.getProdSched()));
        centralNPanel.add(prodSched);

        JPanel centralSPanel = new JPanel();
        centralSPanel.setLayout(new BorderLayout());

        JPanel centralSPanelEast = new JPanel();
        centralSPanelEast.setLayout(new BorderLayout());
        centralSPanelEast.add(new JLabel(INVLIST_HEAD), BorderLayout.NORTH);
        centralSPanelEast.add(new JScrollPane(printCurrInvList()), BorderLayout.CENTER);
        centralSPanelEast.add(addButton, BorderLayout.SOUTH);
        addButton.addActionListener(new AddButton());

        JPanel centralSPanelWest = new JPanel();
        centralSPanelWest.setLayout(new BorderLayout());
        centralSPanelWest.add(new JLabel(PRODINV_HEAD), BorderLayout.NORTH);
        centralSPanelWest.add(new JScrollPane(printProdInvList()), BorderLayout.CENTER);
        centralSPanelWest.add(remButton, BorderLayout.SOUTH);
        remButton.addActionListener(new RemoveButton());

        centralSPanel.add(centralSPanelEast,BorderLayout.WEST);
        centralSPanel.add(centralSPanelWest,BorderLayout.EAST);

        centralPanel.add(centralNPanel,BorderLayout.NORTH);
        centralPanel.add(centralSPanel,BorderLayout.SOUTH);

        //Add content to frame
        editProdFrame.getContentPane().add(headingPanel, BorderLayout.NORTH);
        editProdFrame.getContentPane().add(centralPanel, BorderLayout.CENTER);
        editProdFrame.getContentPane().add(buttonPanel,BorderLayout.SOUTH);
        editProdFrame.setVisible(true);
        editProdFrame.setResizable(false);
        editProdFrame.pack();
    }

    /**
     * JList printCurrInvList() Method:
     * This method is used to print the inventory list that is available to be added for each product.
     * @return Returns the current inventory list in JList form
     *
     */
    public JList printCurrInvList() {
        int listSize = inventory.size();
        currInvLM.setSize(listSize);
        Object[] invData = new Object[listSize];
        for (int i = ZERO; i < listSize; i++) {
            Object rowNum = inventory.get(i).getInvName();
            currInvLM.set(i, rowNum);
            invData[i] = rowNum;
        }
        currInvList = new JList(currInvLM) {
            public boolean isCellEditable(int rowIndex, int colIndex) {
                return false;
            }
        };
        currInvList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        return currInvList;
    }

    /**
     * JList printProdInvList() Method:
     * This method is used to print the inventory list that is currently required for a given product.
     * @return Returns the current inventory required for a product, in JList form.
     *
     */
    public JList printProdInvList() {
        int listSize = currentProduct.getInventList().size();
        prodInvLM.setSize(listSize);
        Object[] invData = new Object[listSize];
        for (int i = ZERO; i < listSize; i++) {
            Object rowNum = currentProduct.getInventList().get(i).getInvName();
            prodInvLM.set(i, rowNum);
            invData[i] = rowNum;
        }
        prodInvList = new JList(prodInvLM) {
            public boolean isCellEditable(int rowIndex, int colIndex) {
                return false;
            }
        };
        prodInvList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        return prodInvList;
    }

    /**
     * DoneButton Inner Class:
     * This inner class is used as a listener to the "Done" button. It is used to confirm the changes made to the product.
     *
     */
    public class DoneButton implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            int prodInvItems = prodInvLM.size();
            currentProduct.setProdName(prodName.getText());
            try {
            currentProduct.setProdCost(Double.parseDouble(prodCost.getText()));
            currentProduct.setProdSched(Integer.parseInt(prodSched.getText()));
            } catch (NumberFormatException x) {
                JOptionPane.showMessageDialog(editProdFrame, INCORRECT_INPUT, ERR, JOptionPane.ERROR_MESSAGE);
                prodCost.setText(EMPTY_STRING);
                prodSched.setText(EMPTY_STRING);
                return;
            }
            try {
                if (prodInvItems == ZERO) {
                    throw new Exception();
                } else {
                    for (int i = ZERO; i<prodInvItems; i++) {
                        currentProduct.setInventList(getInvFromList(prodInvLM,inventory));
                    }
                }
            } catch (Exception x) {
                JOptionPane.showMessageDialog(editProdFrame, NO_INV, ERR, JOptionPane.ERROR_MESSAGE);
                return;
            }
            currViewer.dispose();
            products.addProductAt(currProdInd,currentProduct);
            editProdFrame.dispose();
            new ProductViewer(products, inventory);
        }

    }

    /**
     * InventoryList getInvFromList(DefaultListModel lm, InventoryList inv) Method:
     * This method is used to extract the inventory list from a JList, such that it can be attributed to a given product.
     * @return Returns the inventory list for a product
     *
     */
    public InventoryList getInvFromList(DefaultListModel lm, InventoryList inv) {
        InventoryList productInventory = new InventoryList();
        int prodInvItems = lm.size();
        for (int i = ZERO; i<prodInvItems; i++) {
            String invName = String.valueOf(lm.get(i));
            for (int j = ZERO; j<inv.size(); j++) {
                if (invName.equals(inv.get(j).getInvName())) {
                    productInventory.add(inv.get(j));
                }
            }
        }
        return productInventory;
    }

    /**
     * AddButton Inner Class:
     * This inner class is used as a listener to the "Add" button. It is used to add an inventory item from the current inventory list, into the ivnentory list for the new product.
     *
     */
    public class AddButton implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            try {
            int currInvIndex = currInvList.getSelectedIndex();
            String invName = String.valueOf(currInvLM.get(currInvIndex));
            prodInvLM.addElement(invName);
            prodInvList.revalidate();
            prodInvList.repaint();
            } catch (ArrayIndexOutOfBoundsException ex) {
                JOptionPane.showMessageDialog(editProdFrame, NO_INV_ITEM, ERR, JOptionPane.ERROR_MESSAGE);
                return;
            }
        }

    }

    /**
     * RemoveButton Inner Class:
     * This inner class is used as a listener to the "Remove" button. It is used to remove an inventory item from the product inventory list that is being modified.
     *
     */
    public class RemoveButton implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            try {
            int currProdInvIndex = prodInvList.getSelectedIndex();
            prodInvLM.remove(currProdInvIndex);
            prodInvList.revalidate();
            prodInvList.repaint();
            } catch (ArrayIndexOutOfBoundsException ex) {
                return;
            }
        }

    }

    /**
     * void actionPerformed(ActionEvent e) Method:
     * This is called when the "Cancel" button is pressed. It calls dispose(), which frees up all currently used resources by the current frame (viewProdFrame)
     * and consequently closes it.
     *
     */
    public void actionPerformed(ActionEvent e) {
        products.addProductAt(currProdInd,prodRestore);
        editProdFrame.dispose();
    }

    /**
     * void windowOpened(WindowEvent e) Method:
     * This is one of the abstract methods of the WindowListener class. It has not been implemented.
     *
     */
    public void windowOpened(WindowEvent e) {
    }

    /**
     * void windowClosing(WindowEvent e) Method:
     * This is one of the abstract methods of the WindowListener class. It has been implemented such that if the frame is closed without using the specified "Back"
     * button, the resources used by the frame are released.
     *
     */
    public void windowClosing(WindowEvent e) {
        editProdFrame.dispose();
    }

    /**
     * void windowClosed(WindowEvent e) Method:
     * This is one of the abstract methods of the WindowListener class. It has not been implemented, as its purpose has been covered by the 'windowClosing' event.
     *
     */
    public void windowClosed(WindowEvent e) {
    }

    /**
     * void windowIconified(WindowEvent e) Method:
     * This is one of the abstract methods of the WindowListener class. It has not been implemented.
     *
     */
    public void windowIconified(WindowEvent e) {
    }

    /**
     * void windowDeiconified(WindowEvent e) Method:
     * This is one of the abstract methods of the WindowListener class. It has not been implemented.
     *
     */
    public void windowDeiconified(WindowEvent e) {
    }

    /**
     * void windowActivated(WindowEvent e) Method:
     * This is one of the abstract methods of the WindowListener class. It has not been implemented.
     *
     */
    public void windowActivated(WindowEvent e) {
    }

    /**
     * void windowDeactivated(WindowEvent e) Method:
     * This is one of the abstract methods of the WindowListener class. It has not been implemented.
     *
     */
    public void windowDeactivated(WindowEvent e) {
    }

}
